package FlowGraph.Transformations;

import java.util.*;

import antlr.collections.AST;
import antlr.*;

import FlowGraph.*;
import FlowGraph.Nodes.*;
import JavaGrammar.*;
import SymbolTable.*;
import util.*;

//////////////////////////////////////////////////////////////////////////
//// ForInitializationExtraction
/**

@author Ivan Jeukens
@version v 0.1 12/11/2002
*/
public class ForInitializationExtraction extends Transformation {

    public ForInitializationExtraction(FlowGraph fg) {
        super(fg);
    }

    ///////////////////////////////////////////////////////////////////
    ////                        public  methods                    ////

    /* Para essa transformacao:
       arg0 = o no ForBegin.
    */
    public void transform(FlowGraphNode node) {
        _extractForInitialization(node);
    }

    ///////////////////////////////////////////////////////////////////
    ////                        private methods                    ////

    private void _extractForInitialization(FlowGraphNode node) {
        // Atualiza a AST do node for
        ForBeginNode fbeg = (ForBeginNode) node;
        //ForEndNode end = fbeg.getForEnd();
        LinkedAST forast = (LinkedAST) node.getAbsTreeNode();
        LinkedAST init = (LinkedAST) forast.getFirstChild();

        // System.out.println("Processando o for " + forast.toStringTree());

        if(init.getFirstChild() == null) {
            // Neste caso, nao tem nada na inicializacao ... talvez eu ja
            // tenha tirado (+ de 1 metodo no cond)
            return;
        }
        LinkedAST cond = (LinkedAST) init.getNextSibling();

        // Atualiza o AST do ForBegin
        CommonToken token = new CommonToken(JavaTokenTypes.FOR_INIT, "FOR_INIT");
        LinkedAST newinit = new LinkedAST(token);
        forast.setFirstChild(newinit);
        newinit.setParent(forast);
        newinit.setNextSibling(cond);
        cond.setParent(newinit);

        fbeg.setAbsTreeNode(forast);

        // Remove da ST do for begin eventuais definicoes
        // do for init
        SymbolTable st = new SymbolTable();
        SymbolTable forst = fbeg.getSymbolTable();
        if(fbeg.hasVarDef()) {
            VarDefSearch defsearch = new VarDefSearch();
            Util.inorderTraverse(init, defsearch);

            LinkedList defnames = defsearch.getNames();
            for(int i = 0;i < defnames.size();i++) {
                String s = (String) defnames.get(i);
                Object element = forst.removeElement(s);
                st.putElement(s, element);
            }
            if(forst.localSize() == 0) {
                // O metodo add node before espera nesse caso, que
                // essa entrada e o link de uma tabela antes do for.
                // Assim, tenho que substituir a casca agora oca, por
                // um link para uma tabela superior. Isso tambem vale
                // para os nos do corpo do loop.

                // System.out.println("For st ficou vazia.");

                fbeg.setVarDef(false);

                SymbolTable parentforst = forst.getNextTable();

                //System.out.println("Substituindo por " + 
                //   parentforst.localEntriesToString());

                fbeg.setSymbolTable(parentforst, false);
                SymbolTable.updateNodesST(fbeg, fbeg.getForEnd(),
                    parentforst, forst);
            }
        }

        /*
        System.out.println("A nova st e  : " + st.localEntriesToString());
        System.out.println("A for st e : " + fbeg.getSymbolTable().localEntriesToString());
        */

        LinkedList exprs = _breakInitAST(init);
        BasicBlockNode bb = _newBasicBlock(exprs);

        addNodeBeforeForBegin(bb, st, fbeg, true);
        fbeg.setInitExtractedNode(bb);
        /*
        System.out.println("Ao final do extract init ficou: ");
        System.out.println("Novo no st: " + bb.getSymbolTable().localEntriesToString());
        System.out.println("For st: " + fbeg.getSymbolTable().localEntriesToString());
        */
    }

    ///////////////////////////////////////////////////////////////////
    ////                      private methods                      ////
    
    private LinkedList _breakInitAST(AST init) {
        LinkedList ret = new LinkedList();
        AST ast = init.getFirstChild();
        while(ast != null) {
            AST next = ast.getNextSibling();
            ast.setNextSibling(null);
            if(ast.getType() == JavaTokenTypes.ELIST) {
                LinkedList elist = _breakEList(ast.getFirstChild());
                ret.addAll(elist);
            }
            else {
                ret.add(ast);
            }
            ast = next;
        }
        
        return ret;
    }
    
    ///////////////////////////////////////////////////////////////////
    ////                      private variables                    ////

    class VarDefSearch implements TraverseCall {

        public VarDefSearch() {
            _names = new LinkedList();
        }

        public LinkedList getNames() {
            return _names;
        }

        public void callBack(AST node) {
            if(node != null && 
               node.getType() == JavaTokenTypes.VARIABLE_DEF) {
                AST ast = node.getFirstChild();
                ast = ast.getNextSibling();
                ast = ast.getNextSibling();
                _names.add(ast.getText());
            }
        }

        private LinkedList _names;
    }
}
